package com.hejia.alauda.entity;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.Column;

import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.LocalDate;

/**
 * 金融资产
 * 
 * @author hyr
 *
 */
public class FinancialAsset extends BaseEntity {

	/**
	 * 
	 */
	private static final long serialVersionUID = -880997229724290846L;

	// 产品概述
	@Column
	private String name; // 名称
	@Column
	private BigDecimal amount; // 金额
	@Column
	private BigDecimal inventory; // 库存
	@Column
	private Date valueDate; // 起息日
	@Column
	private Date dueDate; // 到期日
	@Column
	private String publisher; // 发行商
	@Column
	private String productForm; // 产品形式
	@Column
	private String underlyingAsset; // 基础资产
	@Column
	private String managementUnit; // 资产管理机构
	@Column
	private String formingRoute; // 资产形成途径
	@Column
	private String legalOpinion; // 法律意见
	@Column
	private String adviceProvider; // 意见提供机构

	// 基础资产价值评估
	@Column
	private BigDecimal valuation; // 基础资产价值评估（单位元）
	@Column
	private BigDecimal assetCoverage; // 基础资产覆盖率（基础资产/现金流）(单位%)
	@Column
	private String valuationAgency; // 基础资产评估机构

	// 现金流测评
	@Column
	private BigDecimal cashFlowAssessment; // 现金流测评（单位元）
	@Column
	private BigDecimal cashFlowCoverage; // 现金流覆盖率（现金流/本金＋收益）(单位%)
	@Column
	private CashFlowAssessmentResult cashFlowAssessmentResult; // 现金流测评结果
	@Column
	private String cashFlowAssessmentAgency; // 现金流测评机构

	@Column
	private String measureToIncreaseTrust; // 增信措施
	@Column
	private String increaseTrustAgency; // 增信机构

	@Column
	private RiskRating riskRating; // 风险评级
	@Column
	private String riskAssessmentAgency; // 风险测评机构

	@Column
	private String remark; // 备注
	
	@Column
	private String protocolIds; // 协议模版ID集合
	
	@Column
	private Boolean disable; // 是否停用

	private List<Product> products; // 产品列表

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public BigDecimal getAmount() {
		if(amount == null){
			amount = BigDecimal.ZERO;
		}
		return amount;
	}

	public void setAmount(BigDecimal amount) {
		this.amount = amount;
	}
	
	public Date getValueDate() {
		return valueDate;
	}

	public BigDecimal getInventory() {
		return inventory;
	}

	public void setInventory(BigDecimal inventory) {
		this.inventory = inventory;
	}
	
	public void setValueDate(Date valueDate) {
		this.valueDate = valueDate;
	}

	public Date getDueDate() {
		return dueDate;
	}

	public void setDueDate(Date dueDate) {
		this.dueDate = dueDate;
	}

	/**
	 * 获取存续期限(单位天)
	 * 
	 * @return 存续期限
	 */
	public int getDuration() {

		if (this.valueDate == null || this.dueDate == null) {
			return 0;
		}

		LocalDate start = new LocalDate(this.valueDate.getTime());
		LocalDate end = new LocalDate(this.dueDate.getTime());
		return Days.daysBetween(start, end).getDays() + 1;
	}

	public String getPublisher() {
		return publisher;
	}

	public void setPublisher(String publisher) {
		this.publisher = publisher;
	}

	public String getProductForm() {
		return productForm;
	}

	public void setProductForm(String productForm) {
		this.productForm = productForm;
	}

	public String getUnderlyingAsset() {
		return underlyingAsset;
	}

	public void setUnderlyingAsset(String underlyingAsset) {
		this.underlyingAsset = underlyingAsset;
	}

	public String getManagementUnit() {
		return managementUnit;
	}

	public void setManagementUnit(String managementUnit) {
		this.managementUnit = managementUnit;
	}

	public String getFormingRoute() {
		return formingRoute;
	}

	public void setFormingRoute(String formingRoute) {
		this.formingRoute = formingRoute;
	}

	public String getLegalOpinion() {
		return legalOpinion;
	}

	public void setLegalOpinion(String legalOpinion) {
		this.legalOpinion = legalOpinion;
	}

	public String getAdviceProvider() {
		return adviceProvider;
	}

	public void setAdviceProvider(String adviceProvider) {
		this.adviceProvider = adviceProvider;
	}

	public BigDecimal getValuation() {
		return valuation;
	}

	public void setValuation(BigDecimal valuation) {
		this.valuation = valuation;
	}

	public BigDecimal getAssetCoverage() {
		return assetCoverage;
	}
	
	/**
	 * 获取资产覆盖率百分数
	 * @return 资产覆盖率百分数
	 */
	public BigDecimal getAssetCoveragePercent() {
		if(assetCoverage == null){
			return BigDecimal.valueOf(0);
		}
		return assetCoverage.multiply(BigDecimal.valueOf(100));
	}

	public void setAssetCoverage(BigDecimal assetCoverage) {
		this.assetCoverage = assetCoverage;
	}

	public String getValuationAgency() {
		return valuationAgency;
	}

	public void setValuationAgency(String valuationAgency) {
		this.valuationAgency = valuationAgency;
	}

	public BigDecimal getCashFlowAssessment() {
		return cashFlowAssessment;
	}

	public void setCashFlowAssessment(BigDecimal cashFlowAssessment) {
		this.cashFlowAssessment = cashFlowAssessment;
	}

	public BigDecimal getCashFlowCoverage() {
		return cashFlowCoverage;
	}
	
	/**
	 * 获取现金流覆盖率百分数
	 * @return 现金流覆盖率百分数
	 */
	public BigDecimal getCashFlowCoveragePercent() {
		if(cashFlowCoverage == null){
			return BigDecimal.valueOf(0);
		}
		return cashFlowCoverage.multiply(BigDecimal.valueOf(100));
	}

	public void setCashFlowCoverage(BigDecimal cashFlowCoverage) {
		this.cashFlowCoverage = cashFlowCoverage;
	}

	public CashFlowAssessmentResult getCashFlowAssessmentResult() {
		return cashFlowAssessmentResult;
	}

	public void setCashFlowAssessmentResult(
			CashFlowAssessmentResult cashFlowAssessmentResult) {
		this.cashFlowAssessmentResult = cashFlowAssessmentResult;
	}

	public String getCashFlowAssessmentAgency() {
		return cashFlowAssessmentAgency;
	}

	public void setCashFlowAssessmentAgency(String cashFlowAssessmentAgency) {
		this.cashFlowAssessmentAgency = cashFlowAssessmentAgency;
	}

	public String getMeasureToIncreaseTrust() {
		return measureToIncreaseTrust;
	}

	public void setMeasureToIncreaseTrust(String measureToIncreaseTrust) {
		this.measureToIncreaseTrust = measureToIncreaseTrust;
	}

	public String getIncreaseTrustAgency() {
		return increaseTrustAgency;
	}

	public void setIncreaseTrustAgency(String increaseTrustAgency) {
		this.increaseTrustAgency = increaseTrustAgency;
	}

	public RiskRating getRiskRating() {
		return riskRating;
	}

	public void setRiskRating(RiskRating riskRating) {
		this.riskRating = riskRating;
	}

	public String getRiskAssessmentAgency() {
		return riskAssessmentAgency;
	}

	public void setRiskAssessmentAgency(String riskAssessmentAgency) {
		this.riskAssessmentAgency = riskAssessmentAgency;
	}

	public String getRemark() {
		return remark;
	}

	public void setRemark(String remark) {
		this.remark = remark;
	}

	public String getProtocolIds() {
		return protocolIds;
	}

	public void setProtocolIds(String protocolIds) {
		this.protocolIds = protocolIds;
	}
	
	public Boolean getDisable() {
		return disable;
	}

	public void setDisable(Boolean disable) {
		this.disable = disable;
	}
	
	public List<Product> getProducts() {
		if(products == null){
			products = new ArrayList<Product>();
		}
		return products;
	}

	public void setProducts(List<Product> products) {
		this.products = products;
	}
	
	/**
	 * 风险评级
	 * 
	 * @author hyr
	 *
	 */
	public enum RiskRating {

		/**
		 * 谨慎型（基本无风险）
		 */
		R1,

		/**
		 * 稳健性型（风险超低）
		 */
		R2,

		/**
		 * 平衡型（风险低）
		 */
		R3,

		/**
		 * 进取型（风险中）
		 */
		R4,

		/**
		 * 激进型（风险高）
		 */
		R5
	}

	/**
	 * 现金流测评结果
	 * 
	 * @author hyr
	 *
	 */
	public enum CashFlowAssessmentResult {

		/**
		 * 稳定且规则
		 */
		StableAndRule,

		/**
		 * 稳定但不规则(需外部增信)
		 */
		StableButIrregular,

		/**
		 * 不稳定不规则（需外部增信）
		 */
		UnstableIrregular
	}

	/**
	 * 获取资产库存
	 * 按天统计已使用的金融资产，取最大已使用金额求可用库存。
	 * @param valueDate	起息日
	 * @param term		期限（单位天）
	 * @return			库存资产
	 */
	public BigDecimal getInventory(Date valueDate, int term) {
		validParameter(valueDate, term);
		BigDecimal maxAmount = getMaxUsedAmountByDay(valueDate, term);
		return this.amount.subtract(maxAmount);
	}

	/**
	 * 验证参数
	 * @param valueDate	起息日
	 * @param term		期限（单位天）
	 */
	private void validParameter(Date valueDate, int term) {
		
		int valueDateCompare = valueDate.compareTo(this.valueDate);
		int dueDateCompare = valueDate.compareTo(this.dueDate);
		
		if(!(valueDateCompare >= 0 && dueDateCompare <= 0)){
			throw new IllegalArgumentException("起息日不在金融资产存续期间内");
		}
		
		Date dueDate = new Date(new DateTime(valueDate.getTime()).plusDays(term).getMillis());
		valueDateCompare = dueDate.compareTo(this.valueDate);
		dueDateCompare = dueDate.compareTo(this.dueDate);
		
		if(!(valueDateCompare >= 0 && dueDateCompare <= 0)){
			throw new IllegalArgumentException("到期日不在金融资产存续期间内");
		}
	}

	/**
	 * 获取按天计算的最大已使用金额
	 * @param valueDate	起息日
	 * @param term		期限（单位天）
	 * @return			按天计算的最大已使用金额
	 */
	private BigDecimal getMaxUsedAmountByDay(Date valueDate, int term) {
		
		if(this.products == null ||
		   this.products.size() < 1){
			return BigDecimal.ZERO;
		}
		
		BigDecimal max = BigDecimal.ZERO;
		DateTime date = new DateTime(valueDate.getTime());
		for(int i = 0; i < term; i++){
			DateTime day = date.plusDays(i);
			BigDecimal sum = sumUsedAmountByDay(new Date(day.getMillis()));
			if(sum.compareTo(max) == 1){
				max = sum;
			}
		}
		
		return max;
	}

	/**
	 * 计算某天已使用金额之和
	 * @param date	 日期
	 * @return		 某天已使用金额之和
	 */
	private BigDecimal sumUsedAmountByDay(Date date) {
		
		if(this.products == null ||
		   this.products.size() < 1){
			return BigDecimal.ZERO;
		}
		
		BigDecimal sum = BigDecimal.ZERO;
		
		for(Product product : this.products){
			int valueDateCompare = date.compareTo(product.getValueDate());
			Date dueDate = new Date(new DateTime(product.getValueDate()).plusDays(product.getTerm()).getMillis());
			int dueDateCompare = date.compareTo(dueDate);
			if((valueDateCompare == 0 || valueDateCompare > 0) &&
			   (dueDateCompare == 0 || dueDateCompare < 0)){
				sum = sum.add(product.getTotalAmount());
			}
		}
		
		return sum;
	}
}
